﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#include "RMDA_TIME_STRU.h"
#include "../platform/Securec/secinput.h"

namespace {
    const int SLL_YEAR_BEGIN = 2000;
    const int NUMBER_VALUE_SIXTEEN = 16;
    const int NUM2 = 2;
}


U32 SOP_GetHostDateTimeBySt(U32 &ulDate, U32 &ulTime)
{
    SYSTEMTIME st;
    if (memset_s(&st, sizeof(SYSTEMTIME), 0, sizeof(SYSTEMTIME)) != 0) {
        return ERR_SOP_FAILURE;
    }
    FILETIME fileTime;
    FILETIME localFileTime;
    ::GetSystemTimeAsFileTime(&fileTime);
    FileTimeToLocalFileTime(&fileTime, &localFileTime);
    ::FileTimeToSystemTime(&localFileTime, &st);

    ulDate = 0;
    ulTime = 0;

    ulDate = (st.wYear << 16) | ((st.wMonth) << 8) | (st.wDay); // move to the left 16 or 8 bits

    U32 ulSeconds = st.wHour * 60 * 60 + st.wMinute * 60 + st.wSecond; // Modulus of time unit 60

    ulTime = ((ulSeconds << 12) & 0xFFFFF000) | ((st.wMilliseconds) & 0xFFF); // move to the left 12 bits

    return ERR_SOP_SUCCESS;
}
U32 SOP_GetHostDateTime(U32 &ulDate, U32 &ulTime)
{
    // 直接从PC获取时间，不用Hso自身的计时器 (lKF73992/20170113)
    return SOP_GetHostDateTimeBySt(ulDate, ulTime);
}

S64 RMDA_TIME_STRU::GetValMilliSec() const
{
    S64 sllYear = (ulDate >> 16); // move to the right 16 bits
    S64 sllMonth = ((ulDate & 0x0000FFFF) >> 8); // move to the right 8 bits
    S64 sllDay = (ulDate & 0x000000FF);

    S64 sllSeconds = (ulTime & 0xFFFFF000) >> 12; // move to the right 12 bits

    S64 sllMilliseconds = ((ulTime & 0x0FFF));

    BOOL bLeap = IsLeapYear(sllYear);

    S64 sllDayAll;

    if (ulDate == 0) {
        sllDayAll = 0;
    } else {
        RMDA_TIME_STRU *temp = const_cast<RMDA_TIME_STRU *>(this);
        sllDayAll = sllDay - 1 + temp->Year2Day(sllYear) + Month2Day(sllMonth, bLeap);
    }
    // 24 hours 60mins 60s 1000ms
    if (sllDayAll > INT64_MAX / (24 * 60 * 60 * 1000) || sllSeconds > INT64_MAX / 1000) {
        return 0;
    }
    // 24 hours 60mins 60s 1000ms
    S64 sllMillisecondsAll = sllMilliseconds + sllSeconds * 1000 + sllDayAll * 24 * 60 * 60 * 1000;
    return sllMillisecondsAll;
}

S64 RMDA_TIME_STRU::Month2Day(S64 sllMonth, BOOL bLeap)
{
    if (sllMonth < 1 || sllMonth > 12) { // month 1 to 12
        return -1;
    }

    S64 sllDay = 0;

    for (S64 iMonth = 1; iMonth < sllMonth; ++iMonth) {
        sllDay += GetDaysOfAMonth(iMonth, bLeap);
    }

    return sllDay;
}

void RMDA_TIME_STRU::SetValMilliSec(S64 sllMilliSecAll)
{
    S64 sllSecAll = sllMilliSecAll / 1000;   // 1000 ms
    S64 sllMilliSec = sllMilliSecAll % 1000; // 1000 ms

    S64 sllDayAll = sllSecAll / 3600 / 24; //  3600s 24hour
    S64 sllSec = sllSecAll % (3600 * 24);  //  3600s 24hour

    S64 sllMonth = 0;
    S64 sllYear = 0;
    S64 sllDay = 0;
    Day2YearMonthDay(sllDayAll, sllYear, sllMonth, sllDay);

    ulDate = U32((static_cast<U32>(sllYear) << NUMBER_VALUE_SIXTEEN) +
                 (static_cast<U32>(sllMonth) << 8) + sllDay); // move to the left 16 or 8 bits

    ulTime = U32((static_cast<U32>(sllSec) << 12) + sllMilliSec); // move to the left 12 bits

    return;
}

U32 RMDA_TIME_STRU::Day2MonthDay(S64 sllDayAll, S64 &sllMonth, S64 &sllDay, BOOL bLeap)
{
    if (sllDayAll < 0) {
        return ERR_SOP_INVALID_PARAMETERS;
    }

    if (bLeap && sllDayAll >= 366) { // 366 days a years
        return ERR_SOP_INVALID_PARAMETERS;
    }
    if (!bLeap && sllDayAll >= 365) { // 365 days a years
        return ERR_SOP_INVALID_PARAMETERS;
    }

    S64 sllDayCal = 0;
    for (int iMonth = 1; iMonth <= 12; ++iMonth) { // months 1 12
        sllDayCal += GetDaysOfAMonth(iMonth, bLeap);
        if (sllDayCal > sllDayAll) {
            sllMonth = iMonth;

            sllDayCal = sllDayCal - GetDaysOfAMonth(sllMonth, bLeap);

            sllDay = sllDayAll - sllDayCal + 1;

            break;
        }
    }
    return ERR_SOP_SUCCESS;
}

S64 RMDA_TIME_STRU::GetDaysOfAYear(S64 sllYear) const
{
    if ((sllYear % 4) == 0 && (sllYear % 100) != 0) {  // mold 4 && mod 100
        return 366; // 366 days a year
    }
    if ((sllYear % 400) == 0) { // mold 400
        return 366;  // 366 days a year
    }
    return 365; // 365 days a year
}

BOOL RMDA_TIME_STRU::IsLeapYear(const S64 sllYear)
{
    if ((sllYear % 4) == 0 && (sllYear % 100) != 0) {  // mold 4 && mod 100
        return TRUE;
    }
    if ((sllYear % 400) == 0) { // mold 400
        return TRUE;
    }

    return FALSE;
}

S64 RMDA_TIME_STRU::GetDaysOfAMonth(S64 sllMonth, BOOL bLeap)
{
    if (sllMonth < 1 || sllMonth > 12) { // month 1 to 12
        return -1;
    }
    if (sllMonth == 1 || // month 1
        sllMonth == 3 || // month 3
        sllMonth == 5 || // month 5
        sllMonth == 7 || // month 7
        sllMonth == 8 || // month 8
        sllMonth == 10 || // month 10
        sllMonth == 12) { // month 12
        return 31; // 31 days a month
    }
    if (sllMonth == 4 || // month 4
        sllMonth == 6 || // month 6
        sllMonth == 9 || // month 9
        sllMonth == 11) { // month 11
        return 30; // 30 days a month
    }
    if (sllMonth == 2) { // month 2
        if (bLeap) {
            return 29; // 29 days a month
        } else {
            return 28; // 28 days a month
        }
    }
    return -1;
}

S64 RMDA_TIME_STRU::Year2Day(const S64 sllYear) const
{
    S64 sllDay = 0;

    for (S64 iYear = m_sllYearBegin; iYear <= sllYear - 1; ++iYear) {
        sllDay += GetDaysOfAYear(iYear);
    }

    return sllDay;
}

U32 RMDA_TIME_STRU::Day2YearMonthDay(S64 sllDayAll, S64 &sllYear, S64 &sllMonth, S64 &sllDay) const
{
    if (sllDayAll < 0) {
        return ERR_SOP_INVALID_PARAMETERS;
    }

    S64 sllDayCal = 0;

    const S64 sllYearMax = 6000; // max 6000

    for (S64 sllYearCal = m_sllYearBegin; sllYearCal <= sllYearMax; ++sllYearCal) {
        sllDayCal += GetDaysOfAYear(sllYearCal);
        if (sllDayCal > sllDayAll) {
            sllYear = sllYearCal;
            sllDayCal -= GetDaysOfAYear(sllYearCal);
            break;
        }
    }
    S64 sllDayRest = sllDayAll - sllDayCal;
    BOOL bLeap = IsLeapYear(sllYear);
    Day2MonthDay(sllDayRest, sllMonth, sllDay, bLeap);

    return ERR_SOP_SUCCESS;
}

BOOL RMDA_TIME_STRU::operator == (const RMDA_TIME_STRU &other)
{
    if (ulDate != other.ulDate) {
        return FALSE;
    }
    if (ulTime != other.ulTime) {
        return FALSE;
    }

    return TRUE;
}

BOOL RMDA_TIME_STRU::operator != (const RMDA_TIME_STRU &other)
{
    if (ulDate != other.ulDate) {
        return TRUE;
    }
    if (ulTime != other.ulTime) {
        return TRUE;
    }

    return FALSE;
}

BOOL RMDA_TIME_STRU::operator < (const RMDA_TIME_STRU &other)
{
    if (ulDate < other.ulDate) {
        return TRUE;
    } else if (ulDate > other.ulDate) {
        return FALSE;
    }

    if (ulTime < other.ulTime) {
        return TRUE;
    } else {
        return FALSE;
    }
}

BOOL RMDA_TIME_STRU::operator <= (const RMDA_TIME_STRU &other)
{
    if (*this < other || *this == other) {
        return TRUE;
    } else {
        return FALSE;
    }
}

BOOL RMDA_TIME_STRU::operator > (const RMDA_TIME_STRU &other)
{
    return !(*this <= other);
}

BOOL RMDA_TIME_STRU::operator >= (const RMDA_TIME_STRU &other)
{
    return !(*this < other);
}

RMDA_TIME_STRU::RMDA_TIME_STRU()
{
    m_sllYearBegin = SLL_YEAR_BEGIN;

    ulDate = 0;
    ulTime = 0;
}

RMDA_TIME_STRU::RMDA_TIME_STRU(S64 sllYearBegin)
{
    m_sllYearBegin = sllYearBegin;

    ulDate = 0;
    ulTime = 0;
}

void RMDA_TIME_STRU::GetHostDateTime()
{
    SOP_GetHostDateTime(ulDate, ulTime);
}

S64 RMDA_TIME_STRU::operator - (const RMDA_TIME_STRU &other)
{
    S64 sllMe = GetValMilliSec();
    S64 sllOther = other.GetValMilliSec();

    return sllMe - sllOther;
}

QString RMDA_TIME_STRU::FormatDayTimeToColonStr(BOOL bIncludeMilliSec) const
{
    S64 sllHour = 0;
    S64 sllMinute = 0;
    S64 sllSecond = 0;
    S64 sllMilliseconds = 0;

    S64 sllMillisecondAll = GetValMilliSec();

    sllMilliseconds = sllMillisecondAll % 1000; // 1000ms

    S64 sllSecondAll = sllMillisecondAll / 1000;  // 1000ms

    sllSecond = sllSecondAll % 60; // 60s

    S64 sllMiniteAll = sllSecondAll / 60;  // 60s

    sllMinute = sllMiniteAll % 60; // 60s

    S64 sllHourAll = sllMiniteAll / 60; // 60 min

    sllHour = sllHourAll;

    QString strTime;

    if (bIncludeMilliSec) {
        strTime = QString("%1:%2:%3.%4").arg(sllHour, NUM2, 0x0a, QChar('0')).arg(sllMinute,
            NUM2, 0x0a, QChar('0')).arg(sllSecond, NUM2, 0x0a, QChar('0')).arg(sllMilliseconds, NUM2, 0x0a, QChar('0'));
    } else {
        strTime = QString("%1:%2:%3").arg(sllHour, NUM2, 0x0a, QChar('0')).arg(sllMinute,
            NUM2, 0x0a, QChar('0')).arg(sllSecond, NUM2, 0x0a, QChar('0'));
    }
    return strTime;
}
